/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.wsinfra.wse.impl;

import javax.xml.namespace.QName;

import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;

import cgl.narada.wsinfra.exception.WsFaultException;
import cgl.narada.wsinfra.schemas.addressing.EndpointReferenceType;
import cgl.narada.wsinfra.schemas.eventing.GetStatusDocument;
import cgl.narada.wsinfra.schemas.eventing.GetStatusResponseDocument;
import cgl.narada.wsinfra.schemas.eventing.IdentifierDocument;
import cgl.narada.wsinfra.schemas.eventing.NotifyToDocument;
import cgl.narada.wsinfra.schemas.eventing.RenewDocument;
import cgl.narada.wsinfra.schemas.eventing.RenewResponseDocument;
import cgl.narada.wsinfra.schemas.eventing.SubscribeDocument;
import cgl.narada.wsinfra.schemas.eventing.SubscribeResponseDocument;
import cgl.narada.wsinfra.schemas.eventing.SubscriptionEndDocument;
import cgl.narada.wsinfra.schemas.eventing.UnsubscribeDocument;
import cgl.narada.wsinfra.schemas.soap.BodyType;
import cgl.narada.wsinfra.schemas.soap.EnvelopeDocument;
import cgl.narada.wsinfra.schemas.soap.EnvelopeType;
import cgl.narada.wsinfra.schemas.soap.HeaderType;
import cgl.narada.wsinfra.util.QNameLocator;
import cgl.narada.wsinfra.wse.WseFaults;
import cgl.narada.wsinfra.wse.WseNodeUtils;
import cgl.narada.wsinfra.wse.WseQNames;
/**
   A utility class which retrieves the subscription identifier associated
   with an exchange. The method has to throw exceptions, if either the
   identifier is null or is not present. Furthermore, the identifier should
   also be a valid subscription maintained within subscription tables.

   @author Shrideep Pallickara
   $Date: 2005/07/29 22:41:30 $
   $Revision: 1.6 $
*/

public class WseNodeUtilsImpl extends WseNodeUtils {

  private static final WseNodeUtils instance = new WseNodeUtilsImpl();
  private WseFaults wseFaults;
  private WseQNames wseQNames;
  private QNameLocator qNameLocator;

  private String moduleName = "WseNodeUtils: ";

  private WseNodeUtilsImpl() {
     wseFaults = WseFaults.getInstance();
     wseQNames = WseQNames.getInstance();
     qNameLocator = QNameLocator.getInstance();
  }

  public static WseNodeUtils getInstance() {
    return instance;
  }


  /** This method retrieves the SubscribeDocument element from the BODY of
      the SOAP envelope. The method has to throw exceptions, if either the
      element is null or is not present. */
  public SubscribeDocument
  getSubscribeDocument(EnvelopeDocument envelopeDocument)
    throws WsFaultException {

    BodyType bodyType = getEnvelopeBody(envelopeDocument);

    XmlCursor bodyCursor = bodyType.newCursor();
    QName subscribeQName = wseQNames.getSubscribe();
    checkForElement(bodyCursor, subscribeQName);

    boolean creationProblems = false;
    SubscribeDocument subscribeDocument = null;

    try {
      subscribeDocument =
	SubscribeDocument.Factory.parse( bodyCursor.xmlText() );
    } catch (XmlException xmlEx) {
      creationProblems = true;
    }

    bodyCursor.dispose();

    String faultReason="";
    if (subscribeDocument == null || creationProblems) {
      faultReason = "Problems parsing subscribe element";
      throwInvalidMessageFault(faultReason);
    }

    return subscribeDocument;
  }





  /** This method retrieves the SubscribeResponseDocument element from the
      BODY of the SOAP envelope. The method has to throw exceptions, if either
      the element is null or is not present. */
  public SubscribeResponseDocument
  getSubscribeResponseDocument(EnvelopeDocument envelopeDocument)
    throws WsFaultException {

    BodyType bodyType = getEnvelopeBody(envelopeDocument);

    XmlCursor bodyCursor = bodyType.newCursor();
    QName subscribeResponseQName = wseQNames.getSubscribeResponse();
    checkForElement(bodyCursor, subscribeResponseQName);

    boolean creationProblems = false;
    SubscribeResponseDocument subscribeResponseDocument = null;

    try {
      subscribeResponseDocument =
	SubscribeResponseDocument.Factory.parse( bodyCursor.xmlText() );
    } catch (XmlException xmlEx) {
      creationProblems = true;
    }

    bodyCursor.dispose();

    String faultReason="";
    if (subscribeResponseDocument == null || creationProblems) {
      faultReason = "Problems parsing subscribeResponse element";
      throwInvalidMessageFault(faultReason);
    }

    return subscribeResponseDocument;
  }






  /** This method retrieves the RenewDocument element from the BODY of
      the SOAP envelope. The method has to throw exceptions, if either the
      element is null or is not present. */
  public RenewDocument
  getRenewDocument(EnvelopeDocument envelopeDocument)
    throws WsFaultException {

    BodyType bodyType = getEnvelopeBody(envelopeDocument);

    XmlCursor bodyCursor = bodyType.newCursor();
    QName renewQName = wseQNames.getRenew();
    checkForElement(bodyCursor, renewQName);

    boolean creationProblems = false;
    RenewDocument renewDocument = null;

    try {
      renewDocument =
	RenewDocument.Factory.parse( bodyCursor.xmlText() );
    } catch (XmlException xmlEx) {
      creationProblems = true;
    }

    bodyCursor.dispose();

    String faultReason="";
    if (renewDocument == null || creationProblems) {
      faultReason = "Problems parsing renew element";
      throwInvalidMessageFault(faultReason);
    }

    return renewDocument;
  }




  /** This method retrieves the RenewResponseDocument element from the
      BODY of the SOAP envelope. The method has to throw exceptions, if either
      the element is null or is not present. */
  public RenewResponseDocument
  getRenewResponseDocument(EnvelopeDocument envelopeDocument)
    throws WsFaultException {

    BodyType bodyType = getEnvelopeBody(envelopeDocument);

    XmlCursor bodyCursor = bodyType.newCursor();
    QName renewResponseQName = wseQNames.getRenewResponse();
    checkForElement(bodyCursor, renewResponseQName);

    boolean creationProblems = false;
    RenewResponseDocument renewResponseDocument = null;

    try {
      renewResponseDocument =
	RenewResponseDocument.Factory.parse( bodyCursor.xmlText() );
    } catch (XmlException xmlEx) {
      creationProblems = true;
    }

    bodyCursor.dispose();

    String faultReason="";
    if (renewResponseDocument == null || creationProblems) {
      faultReason = "Problems parsing renewResponse element";
      throwInvalidMessageFault(faultReason);
    }

    return renewResponseDocument;
  }




  /** This method retrieves the GetStatusDocument element from the BODY of
      the SOAP envelope. The method has to throw exceptions, if either the
      element is null or is not present. */
  public GetStatusDocument
  getGetStatusDocument(EnvelopeDocument envelopeDocument)
    throws WsFaultException {

    BodyType bodyType = getEnvelopeBody(envelopeDocument);

    XmlCursor bodyCursor = bodyType.newCursor();
    QName getStatusQName = wseQNames.getGetStatus();
    checkForElement(bodyCursor, getStatusQName);

    boolean creationProblems = false;
    GetStatusDocument getStatusDocument = null;

    try {
      getStatusDocument =
	GetStatusDocument.Factory.parse( bodyCursor.xmlText() );
    } catch (XmlException xmlEx) {
      creationProblems = true;
    }

    bodyCursor.dispose();

    String faultReason="";
    if (getStatusDocument == null || creationProblems) {
      faultReason = "Problems parsing getStatus element";
      throwInvalidMessageFault(faultReason);
    }

    return getStatusDocument;
  }



  /** This method retrieves the GetStatusResponseDocument element from the
      BODY of the SOAP envelope. The method has to throw exceptions, if either
      the element is null or is not present. */
  public GetStatusResponseDocument
  getGetStatusResponseDocument(EnvelopeDocument envelopeDocument)
    throws WsFaultException {

    BodyType bodyType = getEnvelopeBody(envelopeDocument);

    XmlCursor bodyCursor = bodyType.newCursor();
    QName getStatusResponseQName = wseQNames.getGetStatusResponse();
    checkForElement(bodyCursor, getStatusResponseQName);

    boolean creationProblems = false;
    GetStatusResponseDocument getStatusResponseDocument = null;

    try {
      getStatusResponseDocument =
	GetStatusResponseDocument.Factory.parse( bodyCursor.xmlText() );
    } catch (XmlException xmlEx) {
      creationProblems = true;
    }

    bodyCursor.dispose();

    String faultReason="";
    if (getStatusResponseDocument == null || creationProblems) {
      faultReason = "Problems parsing getStatusResponse element";
      throwInvalidMessageFault(faultReason);
    }

    return getStatusResponseDocument;
  }



  /** This method retrieves the UnsubscribeDocument element from the BODY of
      the SOAP envelope. The method has to throw exceptions, if either the
      element is null or is not present. */
  public UnsubscribeDocument
  getUnsubscribeDocument(EnvelopeDocument envelopeDocument)
    throws WsFaultException {

    BodyType bodyType = getEnvelopeBody(envelopeDocument);

    XmlCursor bodyCursor = bodyType.newCursor();
    QName unsubscribeQName = wseQNames.getUnsubscribe();
    checkForElement(bodyCursor, unsubscribeQName);

    boolean creationProblems = false;
    UnsubscribeDocument unsubscribeDocument = null;

    try {
      unsubscribeDocument =
	UnsubscribeDocument.Factory.parse( bodyCursor.xmlText() );
    } catch (XmlException xmlEx) {
      creationProblems = true;
    }

    bodyCursor.dispose();

    String faultReason="";
    if (unsubscribeDocument == null || creationProblems) {
      faultReason = "Problems parsing unsubscribe element";
      throwInvalidMessageFault(faultReason);
    }

    return unsubscribeDocument;
  }



  /** This method retrieves the SubscriptionEndDocument element from the BODY
      of the SOAP envelope. The method has to throw exceptions, if either the
      element is null or is not present. */
  public SubscriptionEndDocument
  getSubscriptionEndDocument(EnvelopeDocument envelopeDocument)
    throws WsFaultException {

    BodyType bodyType = getEnvelopeBody(envelopeDocument);

    XmlCursor bodyCursor = bodyType.newCursor();
    QName subscriptionEndQName = wseQNames.getSubscriptionEnd();
    checkForElement(bodyCursor, subscriptionEndQName);

    boolean creationProblems = false;
    SubscriptionEndDocument subscriptionEndDocument = null;

    try {
      subscriptionEndDocument =
	SubscriptionEndDocument.Factory.parse( bodyCursor.xmlText() );
    } catch (XmlException xmlEx) {
      creationProblems = true;
    }

    bodyCursor.dispose();

    String faultReason="";
    if (subscriptionEndDocument == null || creationProblems) {
      faultReason = "Problems parsing subscriptionEnd element";
      throwInvalidMessageFault(faultReason);
    }

    return subscriptionEndDocument;
  }





  /** This method retrieves the identifier element from the HEADER of the
      SOAP envelope. The method has to throw exceptions, if either the element
      is null or is not present. */
  public IdentifierDocument
  getIdentifierDocument(EnvelopeDocument envelopeDocument)
    throws WsFaultException {
    HeaderType headerType = getEnvelopeHeader(envelopeDocument);

    XmlCursor headerCursor = headerType.newCursor();
    QName identifierQName = wseQNames.getIdentifier();
    checkForElement(headerCursor, identifierQName);

    boolean creationProblems = false;
    IdentifierDocument identifierDocument = null;

    try {
      identifierDocument =
	IdentifierDocument.Factory.parse( headerCursor.xmlText() );
    } catch (XmlException xmlEx) {
      creationProblems = true;
    }

    headerCursor.dispose();
    String faultReason = "";

    if (identifierDocument == null || creationProblems) {
      faultReason = "Problems parsing identifier element";
      throwInvalidMessageFault(faultReason);
    }

    String id = identifierDocument.getIdentifier();
    if (id == null) {
      faultReason =
	"The value of the parsed wse:Identifier element is NULL";
      throwInvalidMessageFault(faultReason);
    }

    return identifierDocument;
  }



  /** This method retrieves the identifier element from the BODY of the
      SOAP envelope. The method has to throw exceptions, if either the element
      is null or is not present. */
  public IdentifierDocument
  getIdentifierDocumentFromBody(EnvelopeDocument envelopeDocument)
    throws WsFaultException {
    BodyType bodyType = getEnvelopeBody(envelopeDocument);

    XmlCursor bodyCursor = bodyType.newCursor();
    QName identifierQName = wseQNames.getIdentifier();
    checkForElement(bodyCursor, identifierQName);

    boolean creationProblems = false;
    IdentifierDocument identifierDocument = null;

    try {
      identifierDocument =
	IdentifierDocument.Factory.parse( bodyCursor.xmlText() );
    } catch (XmlException xmlEx) {
      creationProblems = true;
    }

    bodyCursor.dispose();
    String faultReason = "";

    if (identifierDocument == null || creationProblems) {
      faultReason = "Problems parsing identifier element";
      throwInvalidMessageFault(faultReason);
    }

    String id = identifierDocument.getIdentifier();
    if (id == null) {
      faultReason =
	"The value of the parsed wse:Identifier element is NULL";
      throwInvalidMessageFault(faultReason);
    }

    return identifierDocument;
  }


  /** This method tries to retrieve the notifyTo element. The method also
      issues exception in case it is unable to do so or if the retrived
      element is actually null */
  public EndpointReferenceType getNotifyTo(SubscribeDocument subscribeDocument)
    throws WsFaultException {
    String faultReason = "";
    EndpointReferenceType notifyTo = null;

    if (subscribeDocument == null) {
      faultReason = "Problems locating the [wse:NotifyTo] element. Specified " 
	+ "SubscribeDocument is NULL.";
      throwInvalidMessageFault(faultReason);
    }

    XmlCursor subscribeCursor = subscribeDocument.newCursor();
    QName notifyToQName = wseQNames.getNotifyTo();
    checkForElement(subscribeCursor, notifyToQName);
    
    boolean creationProblems = false;
    try {
      NotifyToDocument notifyToDocument =
	NotifyToDocument.Factory.parse(subscribeCursor.xmlText());
      notifyTo = notifyToDocument.getNotifyTo();
    } catch (XmlException xmlEx) {
      creationProblems = true;
    }
    
    subscribeCursor.dispose();
    
    if (notifyTo == null || creationProblems ) {
      faultReason = moduleName + "Problems parsing [wse:notifyTo] element";
    throwInvalidMessageFault(faultReason);
  }

    return notifyTo;
  }


  /** Check to see if the element exists and position the cursor at the
      right location if it does */
  private void checkForElement(XmlCursor xmlCursor, QName qName)
    throws WsFaultException {

    String faultReason = "";
    boolean foundQName = qNameLocator.locateQName(xmlCursor, qName);

    if (!foundQName) {
      xmlCursor.dispose();
      faultReason = "Unable to Locate element [" + qName +
	"], no further processing possible.";
      throwInvalidMessageFault(faultReason);
    }
  }



  /** Checks for problems with the envelope and returns the envelope body */
  private BodyType getEnvelopeBody(EnvelopeDocument envelopeDocument)
    throws WsFaultException {
    String faultReason = "";
    if (envelopeDocument == null) {
      faultReason = "The specified envelope is NULL";
      throwInvalidMessageFault(faultReason);
    }

    BodyType bodyType = envelopeDocument.getEnvelope().getBody();

    if (bodyType == null) {
      faultReason = "The body of SOAP message is NULL!";
      throwInvalidMessageFault(faultReason);
    }

    return bodyType;
  }



   /** Checks for problems with the envelope and returns the envelope body */
  private HeaderType getEnvelopeHeader(EnvelopeDocument envelopeDocument)
    throws WsFaultException {
    String faultReason = "";
    if (envelopeDocument == null) {
      faultReason = "The specified envelope is NULL";
      throwInvalidMessageFault(faultReason);
    }

    EnvelopeType envelope = envelopeDocument.getEnvelope();
    if (!envelope.isSetHeader()) {
      faultReason = "This SOAP message DOES NOT have a header!";
    }

    HeaderType headerType = envelope.getHeader();

    if (headerType == null) {
      faultReason = "The header of the SOAP message is NULL!";
      throwInvalidMessageFault(faultReason);
    }

    return headerType;
  }



  /** Throw a WsFaultException, initialized with the invalid message QName
      and the specified reason */
  private void throwInvalidMessageFault(String reason)
    throws WsFaultException {

    throw
      new WsFaultException(wseFaults.getInvalidMessage(), reason);
  }

}
